package jdklearning.nio.socket;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 选择器是NIO技术的核心组件（缓冲区Buffer、通道Channel、选择器Selector）之一。选择器的主要作用是使用1个线程来对多个通道中的已经就绪通道进行选择，选择出就绪的通道后，就可以对通道中的数据进行处理。选择器核心类包括Selector、SelectionKey、SelectableChannel。
 *
 * 通道的标记SelectionKey
 * 每个注册到选择器中的通道，都有一个代表通道的SelectionKey对象。
 *
 * 可选择通道SelectableChannel
 * ServerSocketChannel
 * SocketChannel
 * DatagramChannel
 * SctpChannel
 * SctpMultiChannel
 * SctpServerChannel
 * SinkChannel
 * SourceChannel
 * 通道的操作类型
 * OP_ACCEPT
 * OP_CONNECT
 * OP_READ
 * OP_WRITE
 *
 * @author shenenlu 2021年03月08日 下午23:25:10
 */
public class SelectorFileTransmissionClient {


    public static void main(String[] args) {
        try {
            SocketChannel socketChannel_1 = SocketChannel.open();
            socketChannel_1.configureBlocking(false);
            socketChannel_1.connect(new InetSocketAddress("localhost", 8088));
            Selector open = Selector.open();
            socketChannel_1.register(open, SelectionKey.OP_CONNECT);
            while (true) {
                open.select();
                Set<SelectionKey> selectionKeys = open.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()) {
                    SelectionKey next = iterator.next();
                    iterator.remove();
                    if (next.isConnectable()) {
                        while (!socketChannel_1.finishConnect()) {
                        }
                        socketChannel_1.register(open, SelectionKey.OP_READ);
                    }
                    if (next.isReadable()) {
                        ByteBuffer allocate = ByteBuffer.allocate(1024);
                        int read = socketChannel_1.read(allocate);
                        while (read !=-1) {
                            read = socketChannel_1.read(allocate);
                        }
                        allocate.flip();
                        if(allocate.remaining() > 0 ) {
                            int isFrame = allocate.getInt();
                            //读取frame
                            if (isFrame == 0) {
                                int anInt = allocate.getInt();
                                System.out.println("filename length = " + anInt);
                                byte[] bytes = new byte[anInt];
                                allocate.get(bytes);
                                System.out.println("filename : " + new String(bytes, "utf8"));
                                long length = allocate.getLong();
                                System.out.println("content length = " + length);
                            }
                            //读取数据,写入本地文件
                            File file = new File("E:\\test001.txt");
                            if(!file.exists()){
                                file.createNewFile();
                            }
                            FileOutputStream fileInputStream = new FileOutputStream(file);
                            FileChannel fileChannel = fileInputStream.getChannel();
                            fileChannel.write(allocate);
                        }
                        allocate.clear();
                    }
                }


            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
